package org.yzh.web.endpoint;

import io.github.yezhihao.netmc.core.annotation.Async;
import io.github.yezhihao.netmc.core.annotation.AsyncBatch;
import io.github.yezhihao.netmc.core.annotation.Endpoint;
import io.github.yezhihao.netmc.core.annotation.Mapping;
import io.github.yezhihao.netmc.session.Session;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.yzh.protocol.basics.JTMessage;
import org.yzh.protocol.commons.JT808;
import org.yzh.protocol.t808.*;
import org.yzh.protocol.t808.utils.T0002MasterElecUtil;
import org.yzh.web.utils.CacheUtil;
import org.yzh.web.utils.DeviceUtil;
import org.yzh.web.model.entity.Device;
import org.yzh.web.model.entity.DeviceDO;
import org.yzh.web.model.enums.SessionKey;
import org.yzh.web.service.IDeviceService;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static org.yzh.protocol.commons.JT808.*;

@Endpoint
@Component
public class JT808Endpoint {

    @Autowired
    private IDeviceService deviceService;

    @Autowired
    private CacheUtil cacheUtil;

    private static final Logger log = LoggerFactory.getLogger(JT808Endpoint.class);

    @Mapping(types = 终端通用应答, desc = "终端通用应答")
    public Object T0001(T0001 message, Session session) {
        session.response(message);
        return null;
    }

    @Mapping(types = 终端心跳, desc = "终端心跳")
    public void T0002(T0002 message, Session session) {
        Device d = deviceService.getDeviceById(message.getClientId());
        if (d != null) {
            d.setHeartbeatTime(new Date());
            if (message.getElectric() != 0){
                d.setElectricPercent(message.getElectric());
            }
            if (message.getMasterElec() != 0){
                message = T0002MasterElecUtil.getMasterElectric(message);
                d.setElectricState(message.getEstate());
                d.setElectricVoltage(message.getEv());
            }
            deviceService.editDevice(d);
            cacheUtil.set(message.getClientId(), d.getDeviceId() + "," + d.getPlateNo());
        }
    }

    @Mapping(types = 终端注销, desc = "终端注销")
    public void T0003(JTMessage message, Session session) {
        cacheUtil.delete(message.getClientId());
        session.invalidate();
    }

    @Mapping(types = 查询服务器时间, desc = "查询服务器时间")
    public T8004 T0004(JTMessage message, Session session) {
        T8004 result = new T8004(LocalDateTime.now(ZoneOffset.UTC));
        return result;
    }

    @Mapping(types = 终端补传分包请求, desc = "终端补传分包请求")
    public void T8003(T8003 message, Session session) {
    }

    @Mapping(types = 终端注册, desc = "终端注册")
    public T8100 T0100(T0100 message, Session session) {
        session.register(message);
        DeviceDO device = new DeviceDO();
        device.setProtocolVersion(message.getProtocolVersion());
        device.setMobileNo(message.getClientId());
        device.setDeviceId(message.getDeviceId());
        device.setPlateNo(message.getPlateNo());
        session.setAttribute(SessionKey.Device, device);

        Device d = deviceService.getDeviceById(message.getClientId());
        if (d == null) {
            d = DeviceUtil.deviceDO2Device(device);
            d.setClientId(message.getClientId());
            deviceService.addDevice(d);
        }else{
            d.setPlateNo(device.getPlateNo());
            d.setMobileNo(device.getMobileNo());
            d.setProtocolVersion(device.getProtocolVersion());
            deviceService.editDevice(d);
        }

        T8100 result = new T8100();
        result.setResponseSerialNo(message.getSerialNo());
        result.setToken(message.getDeviceId() + "," + message.getPlateNo());
        result.setResultCode(T8100.Success);

        log.info("终端注册：{}, token: {}", message.getClientId(), result.getToken());

        cacheUtil.set(message.getClientId(), result.getToken());
        log.info(cacheUtil.get(message.getClientId()));
        return result;
    }

    @Mapping(types = 终端鉴权, desc = "终端鉴权")
    public T0001 T0102(T0102 message, Session session) {
        session.register(message);
        DeviceDO device = new DeviceDO();
        String[] token = message.getToken().split(",");
        device.setProtocolVersion(message.getProtocolVersion());
        device.setMobileNo(message.getClientId());
        device.setDeviceId(token[0]);
        if (token.length > 1)
            device.setPlateNo(token[1]);
        session.setAttribute(SessionKey.Device, device);

        T0001 result = new T0001();
        result.setResponseSerialNo(message.getSerialNo());
        result.setResponseMessageId(message.getMessageId());
        String cacheToken = (String)cacheUtil.get(message.getClientId());
        log.info("缓存中token:"+cacheToken);
        if (cacheToken == null) {
            log.warn("缓存中缺失鉴权：{}", message.getClientId());
            Device d = deviceService.getDeviceById(message.getClientId());
            if (d == null) {
                log.warn("数据库中注册记录：{}", message.getClientId());
                result.setResultCode(T0001.Failure);
            }else{
                cacheToken = d.getDeviceId() + "," + d.getPlateNo();
                cacheUtil.set(message.getClientId(), cacheToken);
            }
        }
        log.info(cacheToken+":"+message.getToken());
        if (Objects.equals(cacheToken, message.getToken())) {
            result.setResultCode(T0001.Success);
            cacheUtil.set(message.getClientId(), message.getToken());
        }else{
            log.warn("终端鉴权失败：{}, token: {}", message.getClientId(), message.getToken());
            result.setResultCode(T0001.Failure);
        }
        return result;
    }

    @Mapping(types = 查询终端参数应答, desc = "查询终端参数应答")
    public void T0104(T0104 message, Session session) {
        session.response(message);
    }

    @Mapping(types = 查询终端属性应答, desc = "查询终端属性应答")
    public void T0107(T0107 message, Session session) {
        Device d = deviceService.getDeviceById(message.getClientId());
        if (d != null){
            d.setIccid(message.getIccid());
            deviceService.editDevice(d);
        }
        session.response(message);
    }

    @Mapping(types = 终端升级结果通知, desc = "终端升级结果通知")
    public void T0108(T0108 message, Session session) {
    }

    /**
     * 异步批量处理
     * poolSize：参考数据库CPU核心数量
     * maxElements：最大累积4000条记录处理一次
     * maxWait：最大等待时间1秒
     */
    @AsyncBatch(poolSize = 2, maxElements = 4000, maxWait = 1000)
    @Mapping(types = 位置信息汇报, desc = "位置信息汇报")
    public void T0200(List<T0200> list) {
        if (list != null && !list.isEmpty()) {
            T0200 message = list.get(list.size() - 1);
            Device d = DeviceUtil.getLocation(message, new Device());
            d.setClientId(message.getClientId());
            deviceService.editDevice(d);
        }
    }

    @Mapping(types = 定位数据批量上传, desc = "定位数据批量上传")
    public void T0704(T0704 message) {
        List<T0200> list = message.getItems();
        if (list != null && !list.isEmpty()) {
            T0200 m = list.get(list.size() - 1);
            Device d = DeviceUtil.getLocation(m, new Device());
            d.setClientId(message.getClientId());
            deviceService.editDevice(d);
        }
    }

    @Mapping(types = {位置信息查询应答, 车辆控制应答}, desc = "位置信息查询应答/车辆控制应答")
    public void T0201_0500(T0201_0500 message, Session session) {
        session.response(message);
    }

    @Mapping(types = 事件报告, desc = "事件报告")
    public void T0301(T0301 message, Session session) {
    }

    @Mapping(types = 提问应答, desc = "提问应答")
    public void T0302(T0302 message, Session session) {
    }

    @Mapping(types = 信息点播_取消, desc = "信息点播/取消")
    public void T0303(T0303 message, Session session) {
    }

}